#ifndef __M_CONNECTION_H__
#define __M_CONNECTION_H__
#include <muduo/base/Logging.h>
#include <muduo/proto/dispatcher.h>
#include <muduo/proto/codec.h>
#include <muduo/base/Mutex.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/base/CountDownLatch.h>
#include "Channel.hpp"
#include "Worker.hpp"
using namespace std;

class Connection 
{
public:
    using ptr = shared_ptr<Connection>;
    // 进行连接的创建实例
    Connection(const string &sip, int sport, const AsyncWorker::ptr &worker)
        : /*_latch(1), */_client(worker->loopthread.startLoop(), 
        muduo::net::InetAddress(sip, sport), "Client"),
        _dispatcher(bind(&Connection::onUnknownMessage, this, placeholders::_1, 
            placeholders::_2, placeholders::_3)),
        _codec(make_shared<ProtobufCodec>( bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
            placeholders::_1, placeholders::_2, placeholders::_3))),
        _worker(worker),
        _channel_manager(make_shared<ChannelManager>())
    {
        // 注册一系列函数
        _dispatcher.registerMessageCallback<MessageQueue::basicCommonResponse>(bind(&Connection::basicResponse, this, 
            placeholders::_1, placeholders::_2, placeholders::_3));
            
        _dispatcher.registerMessageCallback<MessageQueue::basicConsumeResponse>(bind(&Connection::consumeResponse, this, 
            placeholders::_1, placeholders::_2, placeholders::_3));

        _client.setMessageCallback(bind(&ProtobufCodec::onMessage, _codec.get(),
            placeholders::_1, placeholders::_2, placeholders::_3));
        _client.setConnectionCallback(bind(&Connection::onConnection, this, placeholders::_1));      

        _client.connect();
        // _latch.wait();//阻塞等待，直到连接建立成功
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 使用条件变量等待连接建立成功的信号
            _cv.wait(lock, [this]{ return _isConnected; });
        }
        // 此处等待结束，说明连接已经建立成功
    }
    // 打开信道
    Channel::ptr openChannel() 
    {
        Channel::ptr channel = _channel_manager->create(_conn, _codec);
        bool ret = channel->openChannel();
        if (ret == false) 
        {
            lg(Debug, "打开信道失败！");
            return Channel::ptr();
        }
        return channel;
    }
    // 关闭信道
    void closeChannel(const Channel::ptr &channel) 
    {
        channel->closeChannel();
        _channel_manager->remove(channel->cid());
    }

private:
    // 通用响应
    void basicResponse(const muduo::net::TcpConnectionPtr& conn, const basicCommonResponsePtr& message, muduo::Timestamp) 
    {
        // 1. 找到信道
        Channel::ptr channel = _channel_manager->get(message->cid());
        if (channel.get() == nullptr) 
        {
            lg(Debug, "未找到信道信息！");
            return;
        }
        // 2. 将得到的响应对象，添加到信道的基础响应hash_map中
        channel->putBasicResponse(message);
    }
    // 消息的推送
    void consumeResponse(const muduo::net::TcpConnectionPtr& conn, const basicConsumeResponsePtr& message, muduo::Timestamp)
    {
        // 1. 找到信道
        Channel::ptr channel = _channel_manager->get(message->cid());
        if (channel.get() == nullptr) 
        {
            lg(Debug, "未找到信道信息！");
            return;
        }
        // 2. 封装异步任务（消息处理任务），抛入线程池
        _worker->pool.push([channel, message](){
            channel->consume(message);
        });
    }
    // 未知的信息
    void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) 
    {
        LOG_INFO << "onUnknownMessage: " << message->GetTypeName();
        conn->shutdown();
    }
    // 连接
    // void onConnection(const muduo::net::TcpConnectionPtr&conn)
    // {
    //     if (conn->connected()) 
    //     {
    //         _latch.countDown();//唤醒主线程中的阻塞
    //         _conn = conn;
    //     }
    //     else
    //     {
    //         //连接关闭时的操作
    //         _conn.reset();
    //     }
    // }
    void onConnection(const muduo::net::TcpConnectionPtr& conn)
    {
        {
            std::lock_guard<std::mutex> lock(_mutex); // 加锁保护并发访问
            if (conn->connected())
            {
                _conn = conn; // 先赋值
                _isConnected = true; // 设置连接成功标志
                // 唤醒所有等待的线程
                _cv.notify_all(); // 注意这里更改为notify_all，因为可能有多个线程在等待
            }
            else
            {
                // 连接失败，重置_conn
                _conn.reset();
            }
        }
        // 这里解锁会自动进行
    }
public:
    // muduo::CountDownLatch _latch; //实现同步的
    muduo::net::TcpConnectionPtr _conn; //客户端对应的连接
    muduo::net::TcpClient _client; //客户端
    ProtobufDispatcher _dispatcher; //请求分发器
    ProtobufCodecPtr _codec; //协议处理器
    AsyncWorker::ptr _worker;
    ChannelManager::ptr _channel_manager;

    std::mutex _mutex;
    std::condition_variable _cv;
    bool _isConnected = false; // 新增一个标志位表示连接是否建立成功
};

#endif